package com.synjones.idcard;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.ArrayList;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;

import com.synjones.cardutil.util;
import com.synjones.multireaderlib.CmdResponse;
import com.synjones.multireaderlib.MultiReader;
import com.synjones.multireaderlib.IOProtocol.ProtocolType;

import org.apache.log4j.Logger;

/**
 * 身份证操作
* @ClassName IdentityCard 
* @author zhaodianbo@Synjones
* @date 2014-8-26 下午4:07:47 
*
 */
public class IDcardReader{
	MultiReader reader;
	public IDcardReader(MultiReader reader){
		this.reader=reader;
	}
	
	private DecodeAIDLService myAIDLService;
	private boolean mIsBound=false;
	private Context mContext;
	private Bitmap bmp;
	private ServiceConnection Remoteconnection = new ServiceConnection() {  
		  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
            myAIDLService = DecodeAIDLService.Stub.asInterface(service);  
        }  
    };  
	
    /**
     * 打开二代证读卡
    * @Title open 
    * @param mContext
     */
	public void open(Context mContext){

		//setMaxRFByte((byte) 0x50);
		this.mContext=mContext;
		Intent bindIntent = new Intent(mContext, RemoteDecodeService.class);
	 	mContext.bindService(bindIntent, Remoteconnection, Context.BIND_AUTO_CREATE);
		mIsBound=true;
	}
		

	
	
	/** 结束读卡  关闭读卡器
	* @Title: CloseSerialPort    
	* @return void 
	*/
	public void close(){		

		
		try {
    	   	if(mIsBound){
    	    	mContext.unbindService(Remoteconnection);
    			mIsBound=false;
        	}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	
	
	
	/**  获取身份证信息，此函数将阻塞直到返回身份证或读卡超时
	* @Title: getIDcardBlocking   
	* @return IDCard 
	*/
	public IDCard getIDcardBlocking(){
		IDCard card=null;
		try {
			card= getIDCardFp();
			//card.decodeResult=decodeWltStep(card,wltPath, bmpPath);
			if(card==null) return null;
			decodePhoto2Card(card);
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		return card;
	}
	
	public IDCard getIDcardBlockingNoFp(boolean readOnce){
		IDCard card=null;
		try {
			card= getIDCardNoFp(readOnce);
			//card.decodeResult=decodeWltStep(card,wltPath, bmpPath);
			if(card==null) return null;
			decodePhoto2Card(card);
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		return card;
	}
	
	public IDCardReaderRetInfo getIDcardBlockingNoFpRetInfo(boolean readOnce){
		IDCardReaderRetInfo info = null;
		try {
			info = getIDCardNoFpRetInfo(readOnce);
			if(info.errCode!=0) return info;
			decodePhoto2Card(info.card);
		} catch (Exception e) {
			e.printStackTrace();
			info=new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_UNKNOWN);
		}		
		return info;
	}
	
	
	
	public IDCardReaderRetInfo getIDcardBlockingNoFpRetInfo(boolean readOnce,boolean needDecodePhoto){
		IDCardReaderRetInfo info = null;
		try {
			if(needDecodePhoto) 
				return getIDcardBlockingNoFpRetInfo(readOnce);
			info = getIDCardNoFpRetInfo(readOnce);
			if(info.errCode!=0) return info;

		} catch (Exception e) {
			e.printStackTrace();
			info=new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_UNKNOWN);
		}		
		return info;
	}
	
	/**  获取身份证信息，此函数将阻塞直到返回身份证或读卡超时
	* @Title: getIDcardBlocking   
	* @return IDCard 
	*/
	public IDCard getIDcardBlocking(int findtimeout,int selecttimout,int readtimeout){
		IDCard card=null;
		try {
			//IDCard idcard=new IDCard();
			findIDCard(findtimeout);
			selectIDCard(selecttimout);
	/*		if(cr==null || cr.sw[0]!=0 ||cr.sw[1]!=0 || (cr.sw[2]!=(byte)0x90 && cr.sw[2]!=(byte)0x81))
				resp=readBaseMsgFp(200);
			else*/
			card=getIdcardInfo(readBaseMsgFp(readtimeout),true);
			//card.decodeResult=decodeWltStep(card,wltPath, bmpPath);
			if(card==null) return null;
			decodePhoto2Card(card);
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		return card;
	}
	
	 public byte[] decodeWlt(byte wlt[])
    {

	 	if(wlt==null) return null;
        //利用IBinder对象间接调用服务里面的方法
    	try {
			//log("wlt len="+ wlt.length+",byte[]="+util.bytesToHexString(wlt));
			return   myAIDLService.decode(wlt);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//log("decode err"+e.getMessage());
			e.printStackTrace();
		}
         
    	return null;
    }

	private void log(String log){
		Logger.getLogger("OtgTest").error(log);
		//gLogger.error(log);
	}
	 private void decodePhoto2Card(IDCard card){
		byte bmpBytes[]=decodeWlt(card.getWlt());
		if(bmpBytes!=null)
			bmp=BitmapFactory.decodeByteArray(bmpBytes, 0, bmpBytes.length);
		else
			bmp=null;
		card.setPhoto(bmp);
	 }
 
	
	
	/**
	 * 复位SAM_V
	* @Title resetSAM 
	* @return
	 */
	public CmdResponse resetSAM(){
		return reader.doIDcardCmd(0x10,0xff,300);
	}
	
	/**
	 * 设置最大通信字节数
	* @Title setMaxRFByte 
	* @param max
	* @return
	 */
	public CmdResponse setMaxRFByte(int max){
		byte data[]=new byte[1];
		data[0]=(byte) max;
		return reader.doIDcardCmd(0x61, 0xff, data, 300);
	}
	/**
	 * SAM_V状态检测
	* @Title getSAMStatus 
	* @return
	 */
	public CmdResponse getSAMStatus(){
		return reader.doIDcardCmd(0x11, 0xff, 300);
	}
	
	/**
	 * 获取samvID (读SAM_V管理信息)
	* @Title getSAMID 
	* @return
	 */
	public CmdResponse getSAMID() {
		return reader.doIDcardCmd(0x12, 0xff, 300);
	}
	/**
	 * 寻卡
	* @Title findIdcard 
	* @return
	 */
	public CmdResponse findIDCard(){
		return reader.doIDcardCmd(0x20, 0x01, 500);
	}
	public CmdResponse findIDCard(int timeout){
		return reader.doIDcardCmd(0x20, 0x01, timeout);
	}
	
	public void findIDCardNoRep(){
		 reader.sendIDcardCmd(0x20, 0x01,null, 500);
	}

	/**
	 * 选卡
	* @Title selectIdcard 
	* @return
	 */
	public CmdResponse selectIDCard(){
		return reader.doIDcardCmd(0x20, 0x02, 500);
	}
	
	public CmdResponse selectIDCard(int t){
		return reader.doIDcardCmd(0x20, 0x02, t);
	}
	
	public void selectIDCardNoRep(){
		reader.sendIDcardCmd(0x20, 0x02, null,500);
	}
	/**
	 * 读固定信息
	* @Title readBaseMsg 
	* @return
	 */
	public CmdResponse readBaseMsg(){
		return reader.doIDcardCmd(0x30, 0x01, 3500);
	}
	
	/**
	 * 读固定信息和指纹信息
	* @Title readBaseMsgFp 
	* @return
	 */
	public CmdResponse readBaseMsgFp(){
		return reader.doIDcardCmd(0x30, 0x10, 3500);
	}
	
	public CmdResponse readBaseMsgFp(long timeout){
		return reader.doIDcardCmd(0x30, 0x10, timeout);
	}
	public void readBaseMsgFpNoRep(){
		 reader.sendIDcardCmd(0x30, 0x10,null,0);
	}
	
	/**
	 * 读追加地址信息
	* @Title readAppendAdd 
	* @return
	 */
	public CmdResponse readAppendAdd(){
		return reader.doIDcardCmd(0x30, 0x03, 1000);
	}
	
	/**
	 * 获取身份证对象
	* @Title getIDCard 
	* @return
	 */
	public IDCard getIDCard() {
		short textlen = 0, wltlen;
		String dbgmsg = "";
		IDCard idcard=new IDCard();
		byte[] basemsg = null;
		findIDCard();
		selectIDCard();
		CmdResponse resp=readBaseMsg();
		if(resp==null) return null;
		if(!resp.SwIs9000()){
			IDCard.SW1=resp.sw[0];
			IDCard.SW2=resp.sw[1];
			IDCard.SW3=resp.sw[2];
			return null;
		}
		if(resp.getData().length<1284) return null;
		else
		{
			try {
				basemsg = new byte[4+256+1024];
				System.arraycopy(resp.getData(), 0, basemsg, 0, basemsg.length);
			
				textlen = (short) (basemsg[0] * 256 + basemsg[1]);
				wltlen = (short) (basemsg[2] * 256 + basemsg[3]);
				byte[] name = new byte[30];
				System.arraycopy(basemsg, 4, name, 0, name.length);
				idcard.setName(new String(name, "UTF-16LE").trim());
				byte[] sex = new byte[2];
				System.arraycopy(basemsg, 34, sex, 0, sex.length);
				idcard.setSex(new String(sex, "UTF-16LE"));
				if (idcard.getSex().equalsIgnoreCase("1"))
					idcard.setSex("男");
				else
					idcard.setSex("女");
				byte[] nation = new byte[4];
				System.arraycopy(basemsg, 36, nation, 0, nation.length);
				idcard.setNation(idcard.getNationName(new String(nation, "UTF-16LE")));
				byte[] birthday = new byte[16];
				System.arraycopy(basemsg, 40, birthday, 0, birthday.length);
				idcard.setBirthday(new String(birthday, "UTF-16LE"));
				byte[] address = new byte[70];
				System.arraycopy(basemsg, 56, address, 0, address.length);
				idcard.setAddress(new String(address, "UTF-16LE").trim());
				byte[] idcardno = new byte[36];
				System.arraycopy(basemsg, 126, idcardno, 0, idcardno.length);
				idcard.setIDCardNo(new String(idcardno, "UTF-16LE"));
				byte[] grantdept = new byte[30];
				System.arraycopy(basemsg, 162, grantdept, 0, grantdept.length);
				idcard.setGrantDept(new String(grantdept, "UTF-16LE").trim());
				byte[] userlifebegin = new byte[16];
				System.arraycopy(basemsg, 192, userlifebegin, 0, userlifebegin.length);
				idcard.setUserLifeBegin(new String(userlifebegin, "UTF-16LE"));
				byte[] userlifeend = new byte[16];
				System.arraycopy(basemsg, 208, userlifeend, 0, userlifeend.length);
				idcard.setUserLifeEnd(new String(userlifeend, "UTF-16LE").trim());
				byte[] wlt = new byte[1024];
				System.arraycopy(basemsg, textlen+4, wlt, 0, wlt.length);
				idcard.setWlt(wlt);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} 
		return idcard;
	}
	
	/**
	 * 获取包含指纹的二代证信息
	* @Title getIDCardFp 
	* @return
	 */
	public IDCard getIDCardFp() {		
		//IDCard idcard=new IDCard();
		findIDCard();
		CmdResponse cr=selectIDCard();
		CmdResponse resp=null;
/*		if(cr==null || cr.sw[0]!=0 ||cr.sw[1]!=0 || (cr.sw[2]!=(byte)0x90 && cr.sw[2]!=(byte)0x81))
			resp=readBaseMsgFp(200);
		else*/
			resp=readBaseMsgFp();

		
		return getIdcardInfo(resp,true);
	}
	
	public IDCard getIDCardNoFp(boolean readOnce) {		
		//IDCard idcard=new IDCard();
		CmdResponse cr=findIDCard();
		if(cr==null) return null;
		if(readOnce && cr.sw[2]!=(byte)0x9f)
			return null;
		selectIDCard();		
		CmdResponse resp=null;
/*		if(cr==null || cr.sw[0]!=0 ||cr.sw[1]!=0 || (cr.sw[2]!=(byte)0x90 && cr.sw[2]!=(byte)0x81))
			resp=readBaseMsgFp(200);
		else*/
		resp=readBaseMsg();

		
		return getIdcardInfo(resp,false);
	}
	
	/**
	 * read id card
	* @Title getIDCard 
	* @param sameCardReadOnce return error msg if card has been read
	* @param needPhoto need decode photo
	* @param needFp need fingerprint info
	* @return
	 */
	public IDCardReaderRetInfo getIDCardInfo(boolean sameCardReadOnce,boolean needPhoto,boolean needFp){
		if(!needFp) return getIDcardBlockingNoFpRetInfo(sameCardReadOnce, needPhoto);
		IDCardReaderRetInfo ret = getIDCardRetInfo(sameCardReadOnce);
		if(!needPhoto || ret.errCode!=0) return ret;
		decodePhoto2Card(ret.card);
		return ret;
	}
	
	public IDCardReaderRetInfo getIDCardNoFpRetInfo(boolean sameCardReadOnce) {		
		//IDCard idcard=new IDCard();
//		Log.e("test","recv findcard");
		CmdResponse cr=findIDCard();
		if(cr==null) return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_RECV_FINDCARD);
		if(sameCardReadOnce && cr.sw[2]!=(byte)0x9f)
			return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_SAME_CARD, cr.sw);
		Log.e("test","recv selectIDCard");
		selectIDCard();		
		CmdResponse resp=null;
/*		if(cr==null || cr.sw[0]!=0 ||cr.sw[1]!=0 || (cr.sw[2]!=(byte)0x90 && cr.sw[2]!=(byte)0x81))
			resp=readBaseMsgFp(200);
		else*/
		Log.e("test","recv readBaseMsg");
		resp=readBaseMsg();
		if(resp==null )return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_RECV_READBASE);
		if(!resp.SwIs9000() || (resp.SwIs9000() && resp.getData().length<1284) )
			return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_READ_CARD, resp.sw);
		
		return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_OK, getIdcardInfo(resp,false));
	}
	
	public IDCardReaderRetInfo getIDCardRetInfo(boolean sameCardReadOnce) {		
		//IDCard idcard=new IDCard();
		CmdResponse cr=findIDCard();
		if(cr==null) return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_RECV_FINDCARD);
		if(sameCardReadOnce && cr.sw[2]!=(byte)0x9f)
			return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_SAME_CARD, cr.sw);
		selectIDCard();		
		CmdResponse resp=null;
		resp=readBaseMsgFp();
		if(resp==null )return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_RECV_READBASE);
		if(!resp.SwIs9000() || (resp.SwIs9000() && resp.getData().length<1284) )
			return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_READ_CARD, resp.sw);
		
		return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_OK, getIdcardInfo(resp,true));
	}
	
	public IDCardReaderRetInfo getLastBaseMsg(boolean isFpBasemsg){
		CmdResponse resp=reader.getLastCommondResponse(ProtocolType.IDCARD,3000);
		if(resp==null )return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_RECV_READBASE);
		if(!resp.SwIs9000() || (resp.SwIs9000() && resp.getData().length<1284) )
			return new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_READ_CARD, resp.sw);
		IDCardReaderRetInfo ret = new IDCardReaderRetInfo(IDCardReaderRetInfo.ERROR_OK, getIdcardInfo(resp,isFpBasemsg));
		decodePhoto2Card(ret.card);
		return ret;
	}
	
	
	
	public void getIDCardFpNoRep() {		
		//IDCard idcard=new IDCard();
		try {
			findIDCardNoRep();
			Thread.sleep(100);
			selectIDCardNoRep();
			Thread.sleep(100);
			readBaseMsgFpNoRep();	
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	public ArrayList<CmdResponse>  getResponse(byte data[]){
		return reader.recvIDcardCmd(data);
	}
	
	
	public IDCard getIdcardInfo(CmdResponse resp,boolean isFpBasemsg){
		short textlen=0, wltlen=0,fplen = 0;
		//boolean isFpBasemsg=false;
		String dbgmsg = "";
		byte basemsg[]=null;
		IDCard idcard=new IDCard();
		if(resp==null || resp.getData().length<1284) return null;
		if(!resp.SwIs9000()){
			IDCard.SW1=resp.sw[0];
			IDCard.SW2=resp.sw[1];
			IDCard.SW3=resp.sw[2];
			return null;
		}
		else {
			try {
				basemsg=resp.getData();
				textlen = (short) (basemsg[0] * 256 + basemsg[1]);
				wltlen = (short) (basemsg[2] * 256 + basemsg[3]);
				if(isFpBasemsg)
					fplen= (short) (basemsg[4] * 256 + basemsg[5]);
				int varLen=isFpBasemsg?6:4;
				//System.arraycopy(resp.getData(), 0, basemsg, 0, textlen+wltlen+fplen+varLen);
				try {
					byte[] name = new byte[30];
					System.arraycopy(basemsg, varLen, name, 0, name.length);
					idcard.setName(new String(name, "UTF-16LE").trim());
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] sex = new byte[2];
					System.arraycopy(basemsg, varLen+30, sex, 0, sex.length);
					idcard.setSex(new String(sex, "UTF-16LE"));
					if (idcard.getSex().equalsIgnoreCase("1"))
						idcard.setSex("男");
					else
						idcard.setSex("女");
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] nation = new byte[4];
					System.arraycopy(basemsg, varLen+32, nation, 0, nation.length);
					idcard.setNation(idcard.getNationName(new String(nation, "UTF-16LE")));
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] birthday = new byte[16];
					System.arraycopy(basemsg, varLen+36, birthday, 0, birthday.length);
					idcard.setBirthday(new String(birthday, "UTF-16LE"));
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] address = new byte[70];
					System.arraycopy(basemsg, varLen+52, address, 0, address.length);
					idcard.setAddress(new String(address, "UTF-16LE").trim());
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] idcardno = new byte[36];
					System.arraycopy(basemsg, varLen+122, idcardno, 0, idcardno.length);
					idcard.setIDCardNo(new String(idcardno, "UTF-16LE"));
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] grantdept = new byte[30];
					System.arraycopy(basemsg,varLen+ 158, grantdept, 0, grantdept.length);
					idcard.setGrantDept(new String(grantdept, "UTF-16LE").trim());
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] userlifebegin = new byte[16];
					System.arraycopy(basemsg, varLen+188, userlifebegin, 0, userlifebegin.length);
					idcard.setUserLifeBegin(new String(userlifebegin, "UTF-16LE"));
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] userlifeend = new byte[16];
					System.arraycopy(basemsg, varLen+204, userlifeend, 0, userlifeend.length);
					idcard.setUserLifeEnd(new String(userlifeend, "UTF-16LE").trim());
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					byte[] wlt = new byte[wltlen];
					System.arraycopy(basemsg, textlen+varLen, wlt, 0, wltlen);
					idcard.setWlt(wlt);
				} catch (Exception e) {
					e.printStackTrace();
				}
				byte fp[]=null;
				if(fplen>0){
					fp=new byte[fplen];//指纹信息
					System.arraycopy(basemsg, textlen+wltlen+varLen, fp, 0,fplen );
				}
				idcard.setFp(fp);
				Log.d("Sysjones","id card get");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}	
		return idcard;
	}
	
	/**
	 * 获取追加住址信息
	* @Title readAppendAddress 
	* @return
	 */
	public String readAppendAddress(){
		CmdResponse resp=readAppendAdd();
		if(resp==null ||resp.getData().length<70) return "";
		byte AppendAdd[]=new byte[70];
		System.arraycopy(resp.getData(), 0, AppendAdd, 0, AppendAdd.length);
		try {
			if(resp.SwIs9000())
				return new String(AppendAdd, "UTF-16LE");	
			else if(resp.sw[2]==(byte)0x91){
				return "无追加住址";
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
	
	/**
	 * 获取Samv模块编号
	* @Title getSamvIDStr 
	* @return
	 */
	public String getSamvIDStr(){
		CmdResponse resp=getSAMID();
		if(resp==null || !resp.SwIs9000()|| resp.getData().length<16) return "";
		return handleSamv(resp.getData());
	}
	
	public  String handleSamv(byte bsSamId[]){
		byte[] bs1 = new byte[4];
		byte[] bs2 = new byte[5];
		byte[] bs3 = new byte[5];
		byte[] bs4 = new byte[5];
		bs2[4] = 0;
		bs3[4] = 0;
		bs4[4] = 0;
		System.arraycopy(bsSamId, 0, bs1, 0, bs1.length);
		System.arraycopy(bsSamId, 4, bs2, 0, 4);
		System.arraycopy(bsSamId, 8, bs3, 0, 4);
		System.arraycopy(bsSamId, 12, bs4, 0, 4);
		//log.debug("last===========" + new String(bs4));
		BigInteger bi1 = new BigInteger(reverse(bs1));
		BigInteger bi2 = new BigInteger(reverse(bs2));
		BigInteger bi3 = new BigInteger(reverse(bs3));
		BigInteger bi4 = new BigInteger(reverse(bs4));

		String puzzBytes=String.format( "%1d%1d",bs1[3], bs1[2]);
		int puzzInt=Integer.parseInt(puzzBytes);

		String strSamId = String.format(
				"%1d%1d.%02d-%8d-%010d-%010d", bs1[1],
				bs1[0], puzzInt, bi2, bi3, bi4);

		/*String strSamId = String.format(
				"%1d%1d.%1d%1d-%8d-%010d-%010d", bs1[1],
				bs1[0], bs1[3], bs1[2], bi2, bi3, bi4);*/
		return strSamId;
		
	}
	
	private   byte[] reverse(byte[] b) {

		byte[] temp = new byte[b.length];
		for (int i = 0; i < b.length; i++) {
			temp[i] = b[b.length - 1 - i];
		}
		return temp;
	}
	
}